package com.hup.utils.swing.customView;

import com.hup.utils.commons.DateBuilder;
import com.hup.utils.commons.start.LookThemeUtil;
import com.hup.utils.swing.ComponentUtil;
import com.hup.utils.swing.DimensionUtil;
import lombok.Setter;

import javax.swing.*;
import javax.swing.text.DateFormatter;
import javax.swing.undo.UndoManager;
import java.awt.*;
import java.beans.PropertyChangeListener;
import java.util.Date;
import java.util.Objects;

/**
 * <pre>
 * 日期输入栏,提供右键菜单清空数据;
 * JFormattedTextField是一个很弱智的组件,设置格式后,用户无法用键盘清空输入内容!
 * 目前只能使用额外方式(按钮,菜单)进行清空!
 * addPropertyChangeListener("value")也是有bug的
 * @author hugan
 * @date 2019/10/7
 */
public class DateTextField extends JFormattedTextField implements BaseHintText, BaseUndoText {
    private static final long serialVersionUID = -6923091816601980317L;
    private static final String CMD_CLEAN = "清空";

    private UndoManager undoManager;
    /**
     * 修复了swing bug后的监听器
     */
    @Setter
    private ValueChangedListener valueChangedListener;

    public DateTextField() {
        //直接setFormatter()是无效的
        super(new DateFormatter(DateBuilder.strictFormat(DateBuilder.YMD)));
        setFont(new Font(getFont().getName(), getFont().getStyle(), LookThemeUtil.getDefaultScaledFontSize()));
        Dimension dimension = DimensionUtil.getSizeByText(this, DateBuilder.YMD);
        setPreferredSize(dimension);
        setMinimumSize(dimension);
        /*
        setFocusLostBehavior,setInputVerifier
        虽然能实现单一功能,但不能解决实际操作问题,使组件变得'符合人性'
         */
        initListener();
        initMenu();
    }

    private void initListener() {
        initUndo(undoManager = new UndoManager());
        initHintListener();
        super.addPropertyChangeListener("value", evt -> {
            if (Objects.equals(evt.getNewValue(), evt.getOldValue())) {
                //解决value是null时,每次获取焦点都会触发!swing bug!!!
                return;
            }
            if (valueChangedListener != null) {
                valueChangedListener.onChangedValue((Date) getValue());
            }
        });
    }

    private void initMenu() {
        JPopupMenu menu = new JPopupMenu();
        menu.add(new JMenuItem(CMD_CLEAN));
        ComponentUtil.addMenu(this, menu, e -> setValue(null));
    }

    /**
     * 在赋值时,不应该使用这个方法,否则输入监听或valueChange有问题!?, 应使用 {@link #setValue(Date)}
     */
    @Override
    @Deprecated
    public void setText(String t) {
        super.setText(t);
    }

    /**
     * @param value 入参必须是Date
     * @deprecated 用于书写时提示,应使用 {@link #setValue(Date)}
     */
    @Override
    @Deprecated
    public void setValue(Object value) {
        super.setValue(value);
    }

    /**
     * 赋值,会触发valueChanged
     */
    public void setValue(Date value) {
        super.setValue(value);
    }

    /**
     * 目前没发现getText和getValue会有结果不一致的情况
     */
    @Override
    public String getText() {
        return super.getText();
    }

    /**
     * swing原因的valueChanged回调存在bug,不应使用这个方法添加value监听;
     * 使用 {@link #setValueChangedListener(ValueChangedListener)}
     */
    @Override
    @Deprecated
    public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
        super.addPropertyChangeListener(propertyName, listener);
    }

    @Override
    public String getHint() {
        return DateBuilder.YMD;
    }

    @Override
    public void paint(Graphics g) {
        //paint.st -> paintComponent.st,ed -> paint.st
        super.paint(g);
        paintHint(this, g);
    }

    @Override
    public UndoManager getUndoMgr() {
        return undoManager;
    }

    public interface ValueChangedListener {
        void onChangedValue(Date date);
    }

}
